package org.dromara.common.social.topiam

import cn.hutool.core.codec.Base64
import cn.hutool.core.lang.Dict
import cn.hutool.core.util.StrUtil
import cn.hutool.http.HttpRequest
import com.xkcoding.http.support.HttpHeader
import io.github.oshai.kotlinlogging.KotlinLogging
import me.zhyd.oauth.cache.AuthStateCache
import me.zhyd.oauth.config.AuthConfig
import me.zhyd.oauth.exception.AuthException
import me.zhyd.oauth.model.AuthCallback
import me.zhyd.oauth.model.AuthToken
import me.zhyd.oauth.model.AuthUser
import me.zhyd.oauth.request.AuthDefaultRequest
import me.zhyd.oauth.utils.HttpUtils
import me.zhyd.oauth.utils.UrlBuilder
import org.dromara.common.core.utils.SpringUtils.getProperty
import org.dromara.common.json.utils.JsonUtils.parseMap

/**
 * TopIAM 认证请求
 *
 * @author LikeYouDo
 * @date 2025/7/20
 */

/**
 * 设定归属域
 */

open class AuthTopIamRequest : AuthDefaultRequest {
    companion object {
        private val log = KotlinLogging.logger { }

        @JvmField
        val SERVER_URL: String = getProperty("justauth.type.topiam.server-url")

    }

    constructor(config: AuthConfig): super(config, AuthTopIamSource.TOPIAM)

    constructor(config: AuthConfig, authStateCache: AuthStateCache): super(config, AuthTopIamSource.TOPIAM, authStateCache)

    override fun getAccessToken(authCallback: AuthCallback): AuthToken {
        val body = doPostAuthorizationCode(authCallback.code)
        val obj = parseMap(body) ?: throw AuthException("获取用户信息为空")
        checkResponse(obj)
        return AuthToken.builder()
            .accessToken(obj.getStr("access_token"))
            .refreshToken(obj.getStr("refresh_token"))
            .idToken(obj.getStr("id_token"))
            .tokenType(obj.getStr("token_type"))
            .scope(obj.getStr("scope"))
            .build()
    }

    override fun getUserInfo(authToken: AuthToken): AuthUser {
        val body = doGetUserInfo(authToken)
        val obj = parseMap(body) ?: throw AuthException("获取用户信息为空")
        checkResponse(obj)
        return AuthUser.builder()
            .uuid(obj.getStr("sub"))
            .username(obj.getStr("preferred_username"))
            .nickname(obj.getStr("nickname"))
            .avatar(obj.getStr("picture"))
            .email(obj.getStr("email"))
            .token(authToken)
            .source(source.toString())
            .build()
    }

    override fun doPostAuthorizationCode(code: String?): String? {
        val request = HttpRequest.post(source.accessToken())
            .header(
                "Authorization",
                "Basic " + Base64.encode("${config.clientId}:${config.clientSecret}")
            )
            .form("grant_type", "authorization_code")
            .form("code", code)
            .form("redirect_uri", config.redirectUri)
        val response = request.execute()
        return response.body()
    }

    override fun doGetUserInfo(authToken: AuthToken): String {
        return HttpUtils(config.httpConfig).get(
            source.userInfo(), null, HttpHeader()
                .add("Content-Type", "application/json")
                .add("Authorization", "Bearer " + authToken.accessToken), false
        ).body
    }


    override fun authorize(state: String): String {
        return UrlBuilder.fromBaseUrl(super.authorize(state))
            .queryParam("scope", StrUtil.join("%20", config.scopes))
            .build()
    }

    private fun checkResponse(obj: Dict) {
        // oauth/token 验证异常
        if (obj.containsKey("error")) {
            throw AuthException(obj.getStr("error_description"))
        }
        // user 验证异常
        if (obj.containsKey("message")) {
            throw AuthException(obj.getStr("message"))
        }
    }

}
